﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace wspol_zad5
{
    public class ThreadMenager
    {
        public delegate void ChangeProgressBar(int val);

        public ChangeProgressBar ChangeReadersCount;
        public ChangeProgressBar ChangeWritersCount;

        private Resource resource;
        private int bookCount;

        private int readersCount;
        private int writersCount;
        private object readersLocker;
        private object writersLocker;

        private Random rand;

        public ThreadMenager(Resource res)
        {
            resource = res;
            bookCount = resource.Count;

            readersCount = 0;
            writersCount = 0;

            readersLocker = new object();
            writersLocker = new object();

            rand = new Random();
        }

        public void Reader()
        {
            while (true)
            {
                lock (readersLocker)                    
                {
                    while (writersCount > 0) Monitor.Wait(readersLocker);                        
                    Interlocked.Increment(ref readersCount);
                    ChangeReadersCount(readersCount);
                }

                //Dostep do zasobu
                int book = rand.Next(0, bookCount - 1);
                bool succes = resource.RentBook(book);

                if (succes)
                {
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " czyta ksiazke " + book);
                    Thread.Sleep(4000 + rand.Next(-1000, 1000));
                    resource.ReturnBook(book);
                }

                lock (writersLocker)
                    lock (readersLocker)
                    {

                        Interlocked.Decrement(ref readersCount);
                        ChangeReadersCount(readersCount);
                        

                        if (readersCount == 0 && writersCount > 0)
                            Monitor.Pulse(writersLocker);                                               
                    }                

                Thread.Sleep(2000 + rand.Next(-1000, 1000));
            }
        }

        public void Writer()
        {
            while (true)
            {
                lock (writersLocker)
                {
                    Interlocked.Increment(ref writersCount);
                    
                    while (readersCount > 0) Monitor.Wait(writersLocker);                

                    lock (readersLocker)
                    {

                        ChangeWritersCount(writersCount);
                        int book = rand.Next(0, bookCount - 1);
                        bool succes = resource.StartModyfiBook(book);

                        if (succes)
                        {
                            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " poprawia " + book);
                            Thread.Sleep(2000 + rand.Next(-1000, 1000));
                            resource.EndModyfiBook(book);
                        }


                        Interlocked.Decrement(ref writersCount);
                        ChangeWritersCount(writersCount);

                        if (writersCount > 0)
                            Monitor.Pulse(writersLocker);
                        else
                            Monitor.PulseAll(readersLocker);
                    }

                }

                Thread.Sleep(10000 + rand.Next(-2000, 2000));
            }
        }
    }
}
